package main;
import org.neo4j.driver.*;
import static org.neo4j.driver.Values.parameters;
public class Neo4jTest {
    public static void main(String[] args) {
        // 加载驱动
        Driver driver = GraphDatabase.driver("bolt://127.0.0.1:7687", AuthTokens.basic("neo4j", "1234"));
        // 获取连接
        Session session = driver.session();
//        // 统计总数
//        int count = count(session, "MATCH (n) return count(n)");
//        System.out.println("统计总数为：" + count);
        // (1)添加
        long id = createPerson(session, "王五");
        System.out.println("添加id为：" + id);

//        // 查询名称
//        String name = getPersonById(session, id);
//        System.out.println("添加名称为：" + name);
//
//        // (3)修改
//        updatePerson(session, id, "小明");
//
//        // 查询名称
//        name = getPersonById(session, id);
//        System.out.println("修改后名称为：" + name);
//
//       // (2)删除  id=20
//        deletePerson(session, id);
//
//        // (4)执行查询全部  以降序为例
//        queryPerson(session);
//        //补充操作：--->
//        //增加关系
//        createFriendship(session, "小明", "张三");
////      //查询小明的社交关系
//        queryFriendship(session, "小明");
//        //删除关系
//        deleteFriendship(session, "小明", "张三");
         // 释放资源
        session.close();
        driver.close();
    }

    /**
     * 根据id查询名称
     *
     * @param session session
     * @param id      id(内部id)
     * @return name 名称
     */
    private static String getPersonById(Session session, long id) {
        return session.readTransaction(transaction -> {
            Result result = transaction.run("MATCH (a:person) WHERE id(a) = $id return a.name", parameters("id", id));
            return result.single().get(0).asString();
        });
    }

    /**
     * 查询person
     *
     * @param session session
     */
    private static void queryPerson(Session session) {
//        session.run：这是一个执行Cypher查询的方法。
//        查询字符串："MATCH (a:person) RETURN id(a) as id, a.name as name ORDER BY id(a) DESC"。
//        MATCH (a:person)：匹配所有标签为person的节点，并将它们赋值给变量a。
//        RETURN id(a) as id, a.name as name：返回节点a的内部ID（别名为id）和name属性（别名为name）。
//        ORDER BY id(a) DESC：按照节点a的内部ID降序排序返回的结果。
        Result result = session.run("MATCH (a:person) " +
                "RETURN id(a) as id," + "a.name as name ORDER BY id(a) DESC");//order by 默认为升序排列如需降序需加DESC
//        while (result.hasNext())：循环遍历查询结果，直到没有更多的记录。
//        Record record = result.next()：获取下一个记录。
//        int id = record.get("id").asInt()：从记录中获取id字段，并将其转换为int类型。
//        String name = record.get("name").asString()：从记录中获取name字段，并将其转换为String类型。
//        System.out.println("id：" + id + "，name：" + name)：打印节点的ID和名称。
        while (result.hasNext()) {
            Record record = result.next();
            int id = record.get("id").asInt();
            String name = record.get("name").asString();
            System.out.println("id：" + id + "，name：" + name);
        }
    }

    /**
     * 根据id修改名称
     *
     * @param session session
     * @param id      id
     * @param name    name
     */
    private static void updatePerson(Session session, long id, String name) {
        // 执行修改
//        session.writeTransaction：这是一个用来执行写操作的事务方法。它接受一个lambda表达式，该表达式定义了事务中的操作。
//        transaction.run：执行一个Cypher语句来更新节点。
//        "MATCH (n) WHERE id(n) = $id SET n.name = $name"：这是Cypher查询语句，它执行以下操作：
//        MATCH (n)：匹配图中的所有节点，并将它们赋值给变量n。
//        WHERE id(n) = $id：过滤条件，只有当节点n的内部ID等于参数$id时，该节点才会被选中。
//        SET n.name = $name：将匹配节点的name属性设置为参数$name的值
        session.writeTransaction(transaction -> {
            transaction.run("MATCH (n) WHERE id(n) = $id SET n.name = $name", parameters("id", id, "name", name));
            return null;
        });
    }

    /**
     * 根据id删除person
     *
     * @param session session
     * @param id      id
     */
    private static void deletePerson(Session session, long id) {
        // 执行删除
//        session.writeTransaction：这是一个用来执行写操作的事务方法。它接受一个lambda表达式，该表达式定义了事务中的操作。
//        transaction.run：执行一个Cypher语句来删除节点。
//        "MATCH (n) WHERE id(n) = $id DELETE n"：这是Cypher查询语句，它执行以下操作：
//        MATCH (n)：匹配图中的所有节点，并将它们赋值给变量n。
//        WHERE id(n) = $id：过滤条件，只有当节点n的内部ID等于参数$id时，该节点才会被选中。
//        DELETE n：删除匹配的节点。
        session.writeTransaction(transaction -> {
            transaction.run("MATCH (n) WHERE id(n) = $id DELETE n", parameters("id", id));
//            transaction.run("MATCH (n) WHERE id(n) = $id REMOVE n.name", parameters("id", id));
            return null;
        });
    }

    /**
     * 添加person
     *
     * @param session session
     * @param name    名称
     * @return id
     */
    private static long createPerson(Session session, String name) {
        // 执行添加
//        session.writeTransaction：这是一个用来执行写操作的事务方法。它接受一个lambda表达式，该表达式定义了事务中的操作。
//        transaction.run：执行一个Cypher语句来创建一个新的person节点，节点有一个属性name，其值由方法参数name提供。
//        parameters("name", name)：这是参数化查询的参数，将name变量的值传递给Cypher查询中的$name参数。
        session.writeTransaction(transaction -> {
            transaction.run("CREATE (a:person {name: $name})", parameters("name", name));
            return null;
        });
//        session.readTransaction：这是一个用来执行读操作的事务方法。它也接受一个lambda表达式，该表达式定义了事务中的操作。
//        transaction.run：执行一个Cypher查询，查找刚才创建的person节点，并返回该节点的内部ID
//        result.single()：从查询结果中提取单个记录。这里假设查询结果恰好有一个记录，即刚刚创建的节点。
//        .get(0)：获取结果集中的第一个字段，即节点的内部ID。
//        .asLong()：将字段值转换为long类型，这是Neo4j节点内部ID的数据类型
        return session.readTransaction(transaction -> {
            Result result = transaction.run("MATCH (a:person {name: $name}) RETURN id(a)", parameters("name", name));
            return result.single().get(0).asLong();
        });
    }

    /**
     * 统计
     *
     * @param session session
     * @param query   查询语句
     * @return 数量
     */
    private static int count(Session session, String query) {
        return session.readTransaction(transaction -> transaction.run(query, Values.parameters()).single().get(0).asInt());
    }

    private static void createFriendship(Session session, String name1, String name2) {
        // 添加关系
//        session.writeTransaction：这是一个用来执行写操作的事务方法。它接受一个lambda表达式，该表达式定义了事务中的操作。
//        transaction.run：执行一个Cypher语句来创建关系。
//        "MATCH (a:person {name: $name1}), (b:person {name: $name2})"：这部分匹配两个标签为person的节点，节点的name属性分别与方法参数name1和name2相匹配，并将这些节点赋值给变量a和b。
//        "CREATE (a)-[:KNOWS]->(b)"：这部分创建一个从节点a指向节点b的KNOWS类型关系。
        session.writeTransaction(transaction -> {
            transaction.run("MATCH (a:person {name: $name1}), (b:person {name: $name2})" +
                    "CREATE (a)-[:KNOWS]->(b)", parameters("name1", name1, "name2", name2));
            return null;
        });
    }

    private static void queryFriendship(Session session, String name) {
        //查询关系
//        session.run：这是一个执行Cypher查询的方法。
//        查询字符串："MATCH (a:person {name: $name})-[:KNOWS]->(friends) RETURN id(friends) as id, friends.name as name"。
//        MATCH (a:person {name: $name})：匹配一个标签为person且属性name与方法参数name相匹配的节点，并将其赋值给变量a。
//        -[:KNOWS]->(friends)：匹配从节点a出发，通过KNOWS类型的关系指向的节点（即朋友节点），并将这些节点赋值给变量friends。
//        RETURN id(friends) as id, friends.name as name：返回朋友节点的内部ID（别名为id）和name属性（别名为name）。
        Result result = session.run("MATCH (a:person {name: $name})-[:KNOWS]->(friends)" +
                "RETURN id(friends) as id," + " friends.name as name", parameters("name", name));
//         while (result.hasNext()):
//        这个循环遍历查询结果。
//        Record record = result.next();
//        获取查询结果的下一条记录。
//        int id = record.get("id").asInt();
//        从当前记录中获取id字段，并将其转换为整数。
//        String name1 = record.get("name").asString();
//        从当前记录中获取name字段，并将其转换为字符串。
//        System.out.println("id：" + id + "，name：" + name1);
//        打印出每个朋友节点的ID和名称。
        System.out.println(name + "朋友包括：\n");
        while (result.hasNext()) {
            Record record = result.next();
            int id = record.get("id").asInt();
            String name1 = record.get("name").asString();
            System.out.println("id：" + id + "，name：" + name1);
        }
    }

    private static void deleteFriendship(Session session, String name1, String name2) {
        // 删除关系
        session.writeTransaction(transaction -> {
            transaction.run("MATCH (a:person {name: $name1})-[r:KNOWS]->(b:person {name: $name2})\n" +
                    "DELETE r", parameters("name1", name1, "name2", name2));
            return null;
        });
    }
}
